#pragma once
#include <d3dx9math.h>

class Camera
{

public:
	static const float DEFAULT_FIRST_PERSON_OFFSET;
	static const float DEFAULT_TOP_DOWN_OFFSET;
	static const float DEFAULT_ROTATION_SPEED;
    static const float DEFAULT_FOVX;
    static const float DEFAULT_ZNEAR;
    static const float DEFAULT_ZFAR;
    static const D3DXVECTOR3 WORLD_XAXIS;
    static const D3DXVECTOR3 WORLD_YAXIS;
    static const D3DXVECTOR3 WORLD_ZAXIS;

private:

    float m_rotationSpeed;
    float m_fovx;
    float m_aspectRatio;
    float m_znear;
    float m_zfar;

	D3DXVECTOR3 m_AxisX;
    D3DXVECTOR3 m_AxisY;
    D3DXVECTOR3 m_AxisZ;
    D3DXVECTOR3 m_viewDir;
    
	D3DXVECTOR3 m_velocity;
	D3DXVECTOR3 m_curVelocity;
	D3DXVECTOR3 m_acceleration;

    D3DXQUATERNION m_orientation;
    D3DXMATRIX m_viewMatrix;
    D3DXMATRIX m_projMatrix;
    D3DXMATRIX m_viewProjMatrix;

public:
	enum CameraMode
    {
        CAM_MODE_FIRST_PERSON,
        CAM_MODE_TOPDOWN,
        CAM_MODE_FLIGHT,
    };

	Camera(void);
	~Camera(void);

	void setMode(CameraMode mode);
	void switchMode(void);
	bool isFirstPerson(void);
	bool isTopDown(void);

	const D3DXVECTOR3 &getCurrentVelocity() const;
	const D3DXVECTOR3 &getPosition() const;
    const D3DXVECTOR3 &getViewDirection() const;
    const D3DXMATRIX  &getViewMatrix() const;
    const D3DXMATRIX  &getViewProjectionMatrix() const;
	const D3DXMATRIX  &getProjectionMatrix() const;
    const D3DXVECTOR3 &getXAxis() const;
    const D3DXVECTOR3 &getYAxis() const;
    const D3DXVECTOR3 &getZAxis() const;

	void lookAt(const D3DXVECTOR3 &target);
    void lookAt(const D3DXVECTOR3 &eye, const D3DXVECTOR3 &target, const D3DXVECTOR3 &up);
    void move(float dx, float dy, float dz);
    void move(const D3DXVECTOR3 &direction, const D3DXVECTOR3 &amount);
	void rotate(float headingDeg, float pitchDeg, float rollDeg);

	void setPosition(const D3DXVECTOR3 &newPos);
    void setOrientation(const D3DXQUATERNION &newOrientation);
    void setRotationSpeed(float rotationSpeed);
	void setPerspective(float fovx, float aspect, float znear, float zfar);

	void setAcceleration(const D3DXVECTOR3 &acceleration);
    void setCurrentVelocity(const D3DXVECTOR3 &currentVelocity);
    void setCurrentVelocity(float x, float y, float z);
    void setVelocity(const D3DXVECTOR3 &velocity);
    void setVelocity(float x, float y, float z);

	const D3DXVECTOR3 getDisplacement(const D3DXVECTOR3 &direction, float elapsedTimeSec) const;
	void updatePosition(const D3DXVECTOR3 &direction, float elapsedTimeSec);
	void updateVelocity(const D3DXVECTOR3 &direction, float elapsedTimeSec);
	
	void updateViewMatrix(void);

	D3DXVECTOR3 m_pos; // eye position
	CameraMode mode;

};

inline const D3DXVECTOR3 &Camera::getCurrentVelocity() const { return m_curVelocity; }
inline const D3DXVECTOR3 &Camera::getPosition() const { return m_pos; }
inline const D3DXMATRIX &Camera::getViewMatrix() const { return m_viewMatrix; }
inline const D3DXMATRIX &Camera::getProjectionMatrix() const { return m_projMatrix; }



